package org.hackystat.sdsa.analyzer.control.processor;

import java.util.ArrayList;
import java.util.List;
import java.util.logging.Level;
import java.util.logging.Logger;

import org.hackystat.sdsa.analyzer.SdsaAnalyzerException;
import org.hackystat.sdsa.analyzer.model.activity.Activity;
import org.hackystat.sensorbase.resource.sensordata.jaxb.Properties;
import org.hackystat.sensorbase.resource.sensordata.jaxb.Property;
import org.hackystat.sensorbase.resource.sensordata.jaxb.SensorData;

/**
 * Defines an ActivityBuilder to build activities out of sensor data.
 * 
 * @author hongbing
 *
 */
public class ActivityBuilder {
  /** A list of activities. */
  private List<Activity> activityList;
  /** List of processors. */
  private List<Processor> processors;
  /** The logger */
  private Logger logger;
  
  /**
   * Constructor of the activity builder.
   * 
   * @param logger Service logger.
   */
  public ActivityBuilder(Logger logger) {
    this.logger = logger;
    
    this.activityList = new ArrayList<Activity>();
    
    this.processors = new ArrayList<Processor>();
    this.processors.add(new BuffTransActivityProcessor());
    this.processors.add(new CompilationActivityProcessor());
    this.processors.add(new EditActivityProcessor());
    this.processors.add(new RefactoringActivityProcessor());
    this.processors.add(new UnitTestActivityProcessor());
  }
  
  /**
   * Processes the sensor data that could be any DevEvent.
   * 
   * @param sensorData Sensor data.
   * @throws SdsaAnalyzerException If error in processing the sensor data.
   */
  public void process(SensorData sensorData) throws SdsaAnalyzerException {
    try {
      for (Processor processor : this.processors) {
        if (processor.processable(sensorData)) {
          Activity activity = processor.process(sensorData, logger);
          this.activityList.add(activity);
        }
      }
    }
    catch (Throwable t) {
      String sensorDataString = data2String(sensorData);
      this.logger.log(Level.WARNING, "Failed to process sensor data : " + sensorDataString, t);
      throw new SdsaAnalyzerException("Failed to process sensor data : " + sensorDataString, t);
    }
  }
  
  /**
   * Logs the sensor data out.
   * 
   * @param sensorData Sensor data.
   * @return Sensor data in string.
   */
  private String data2String(SensorData sensorData) {
    StringBuffer buf = new StringBuffer();
    buf.append('\n');
    buf.append(sensorData.getTimestamp());
    buf.append('\n').append(sensorData.getResource());
    buf.append('\n').append(sensorData.getSensorDataType());
    
    Properties props = sensorData.getProperties();
    for (Property prop : props.getProperty()) {
      buf.append("\n\t").append(prop.getKey()).append('=').append(prop.getValue());
    }
    
    return buf.toString();
  }
  
  /**
   * Gets the list of activities.
   * 
   * @return A list of activities.
   */
  public List<Activity> getActivityList() {
    return this.activityList;
  }
}
